home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / bumpmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-08  |  47.2 KB  |  1,831 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Bump map plug-in --- emboss an image by using another image as a bump map
  5.  * Copyright (C) 1997 Federico Mena Quintero <federico@nuclecu.unam.mx>
  6.  * Copyright (C) 1997-2000 Jens Lautenbacher <jtl@gimp.org>
  7.  * Copyright (C) 2000 Sven Neumann <sven@gimp.org>
  8.  * 
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23.  */
  24.  
  25.  
  26. /* This plug-in uses the algorithm described by John Schlag, "Fast
  27.  * Embossing Effects on Raster Image Data" in Graphics Gems IV (ISBN
  28.  * 0-12-336155-9).  It takes a grayscale image to be applied as a
  29.  * bump-map to another image, producing a nice embossing effect.
  30.  */
  31.  
  32. /* Version 3.0-pre1-ac2:
  33.  *
  34.  * - waterlevel/ambient restricted to 0-255
  35.  * - correctly initialize bumpmap_offsets
  36.  */   
  37.  
  38. /* Version 3.0-pre1-ac1:
  39.  *
  40.  * - Now able not to tile the bumpmap - this is the default.
  41.  * - Added new PDB call plug_in_bumpmap_tiled.
  42.  * - Added scrollbars for preview.
  43.  * - Fixed slider feedback for bumpmap offset and set initial offsets
  44.  *   from drawable offsets.
  45.  * - Make it work as intended from the very beginning...
  46.  */
  47.   
  48. /* Version 2.04:
  49.  *
  50.  * - The preview is now scrollable via draging with button 1 in the
  51.  * preview area. Thanks to Quartic for helping with gdk event handling.
  52.  *
  53.  * - The bumpmap's offset can alternatively be adjusted by dragging with
  54.  * button 3 in the preview area.
  55.  */
  56.  
  57. /* Version 2.03:
  58.  *
  59.  * - Now transparency in the bumpmap drawable is handled as specified
  60.  * by the waterlevel parameter.  Thanks to Jens for suggesting it!
  61.  *
  62.  * - New cool ambient lighting method.  Thanks to Jens Lautenbacher
  63.  * for creating it!  Something useful actually came out of those IRC
  64.  * sessions ;-)
  65.  *
  66.  * - Added proper rounding wherever it seemed appropriate.  This fixes
  67.  * some minor artifacts in the output.
  68.  */
  69.  
  70.  
  71. /* Version 2.02:
  72.  *
  73.  * - Fixed a stupid bug in the preview code (offsets were not wrapped
  74.  * correctly in some situations).  Thanks to Jens Lautenbacher for
  75.  * reporting it!
  76.  */
  77.  
  78.  
  79. /* Version 2.01:
  80.  *
  81.  * - For the preview, vertical scrolling and setting the vertical
  82.  * bumpmap offset are now *much* faster.  Instead of calling
  83.  * gimp_pixel_rgn_get_row() a lot of times, I now use an adapted
  84.  * version of gimp_pixel_rgn_get_rect().
  85.  */
  86.  
  87.  
  88. /* Version 2.00:
  89.  *
  90.  * - Rewrote from the 0.54 version (well, from the 0.99.9
  91.  * distribution, actually...).  New in this release are the correct
  92.  * handling of all image depths, sizes, and offsets.  Also the
  93.  * different map types, the compensation and map inversion options
  94.  * were added.  The preview widget is new, too.
  95.  */
  96.  
  97.  
  98. /* TODO:
  99.  *
  100.  * - Speed-ups
  101.  */
  102.  
  103. #include "config.h"
  104.  
  105. #include <stdio.h>
  106. #include <stdlib.h>
  107. #include <string.h>
  108. #ifdef HAVE_UNISTD_H
  109. #include <unistd.h>
  110. #endif
  111.  
  112. #include <gtk/gtk.h>
  113.  
  114. #include <libgimp/gimp.h>
  115. #include <libgimp/gimpui.h>
  116.  
  117. #include "libgimp/stdplugins-intl.h"
  118.  
  119.  
  120. /***** Magic numbers *****/
  121.  
  122. #define PLUG_IN_VERSION "April 2000, 3.0-pre1-ac2"
  123.  
  124. #define PREVIEW_SIZE    128
  125. #define SCALE_WIDTH       0
  126.  
  127. /***** Types *****/
  128.  
  129. enum
  130. {
  131.   LINEAR = 0,
  132.   SPHERICAL,
  133.   SINUOSIDAL
  134. };
  135.  
  136. enum
  137. {
  138.   DRAG_NONE = 0,
  139.   DRAG_SCROLL,
  140.   DRAG_BUMPMAP
  141. };
  142.  
  143. typedef struct
  144. {
  145.   gint32  bumpmap_id;
  146.   gdouble azimuth;
  147.   gdouble elevation;
  148.   gint    depth;
  149.   gint    xofs;
  150.   gint    yofs;
  151.   gint    waterlevel;
  152.   gint    ambient;
  153.   gint    compensate;
  154.   gint    invert;
  155.   gint    type;
  156.   gint    tiled;
  157. } bumpmap_vals_t;
  158.  
  159. typedef struct
  160. {
  161.   gint    lx, ly;       /* X and Y components of light vector */
  162.   gint    nz2, nzlz;    /* nz^2, nz*lz */
  163.   gint    background;   /* Shade for vertical normals */
  164.   gdouble compensation; /* Background compensation */
  165.   guchar  lut[256];     /* Look-up table for modes */
  166. } bumpmap_params_t;
  167.  
  168. typedef struct
  169. {
  170.   GtkWidget   *preview;
  171.   GtkObject   *preview_adj_x;
  172.   GtkObject   *preview_adj_y;
  173.   gint         preview_width;
  174.   gint         preview_height;
  175.   gint         mouse_x;
  176.   gint         mouse_y;
  177.   gint         preview_xofs;
  178.   gint         preview_yofs;
  179.   gint         drag_mode;
  180.  
  181.   GtkObject   *offset_adj_x;
  182.   GtkObject   *offset_adj_y;
  183.   
  184.   guchar      *check_row_0;
  185.   guchar      *check_row_1;
  186.  
  187.   guchar     **src_rows;
  188.   guchar     **bm_rows;
  189.  
  190.   gint         src_yofs;
  191.   gint         bm_yofs;
  192.  
  193.   GimpDrawable   *bm_drawable;
  194.   gint         bm_width;
  195.   gint         bm_height;
  196.   gint         bm_bpp;
  197.   gint         bm_has_alpha;
  198.  
  199.   GimpPixelRgn    src_rgn;
  200.   GimpPixelRgn    bm_rgn;
  201.  
  202.   bumpmap_params_t params;
  203.  
  204.   gint         run;
  205. } bumpmap_interface_t;
  206.  
  207.  
  208. /***** Prototypes *****/
  209.  
  210. static void query (void);
  211. static void run   (gchar   *name,
  212.            gint     nparams,
  213.            GimpParam  *param,
  214.            gint    *nreturn_vals,
  215.            GimpParam **return_vals);
  216.  
  217. static void bumpmap             (void);
  218. static void bumpmap_init_params (bumpmap_params_t *params);
  219. static void bumpmap_row         (guchar           *src_row,
  220.                  guchar           *dest_row,
  221.                  gint              width,
  222.                  gint              bpp,
  223.                  gint              has_alpha,
  224.                  guchar           *bm_row1,
  225.                  guchar           *bm_row2,
  226.                  guchar           *bm_row3,
  227.                  gint              bm_width,
  228.                  gint              bm_xofs,
  229.                  gboolean          tiled,
  230.                  gboolean          row_in_bumpmap,       
  231.                  bumpmap_params_t *params);
  232. static void bumpmap_convert_row (guchar           *row,
  233.                  gint              width,
  234.                  gint              bpp,
  235.                  gint              has_alpha,
  236.                  guchar           *lut);
  237.  
  238. static gint bumpmap_dialog              (void);
  239. static void dialog_init_preview         (void);
  240. static void dialog_new_bumpmap          (gboolean init_offsets);
  241. static void dialog_update_preview       (void);
  242. static gint dialog_preview_events       (GtkWidget *widget, GdkEvent *event);
  243. static void dialog_scroll_src           (void);
  244. static void dialog_scroll_bumpmap       (void);
  245. static void dialog_get_rows             (GimpPixelRgn *pr, guchar **rows,
  246.                      gint x, gint y,
  247.                      gint width, gint height);
  248. static void dialog_fill_src_rows        (gint start, gint how_many, gint yofs);
  249. static void dialog_fill_bumpmap_rows    (gint start, gint how_many, gint yofs);
  250.  
  251. static void dialog_compensate_callback  (GtkWidget *widget, gpointer data);
  252. static void dialog_invert_callback      (GtkWidget *widget, gpointer data);
  253. static void dialog_tiled_callback       (GtkWidget *widget, gpointer data);
  254. static void dialog_map_type_callback    (GtkWidget *widget, gpointer data);
  255. static gint dialog_constrain            (gint32 image_id, gint32 drawable_id,
  256.                      gpointer data);
  257. static void dialog_bumpmap_callback     (gint32 id, gpointer data);
  258. static void dialog_dscale_update        (GtkAdjustment *adjustment,
  259.                      gdouble *value);
  260. static void dialog_iscale_update_normal (GtkAdjustment *adjustment, gint *value);
  261. static void dialog_iscale_update_full   (GtkAdjustment *adjustment, gint *value);
  262. static void dialog_ok_callback          (GtkWidget *widget, gpointer data);
  263.  
  264. /***** Variables *****/
  265.  
  266. GimpPlugInInfo PLUG_IN_INFO =
  267. {
  268.   NULL,  /* init_proc  */
  269.   NULL,  /* quit_proc  */
  270.   query, /* query_proc */
  271.   run    /* run_proc   */
  272. };
  273.  
  274. static bumpmap_vals_t bmvals =
  275. {
  276.   -1,     /* bumpmap_id */
  277.   135.0,  /* azimuth */
  278.   45.0,   /* elevation */
  279.   3,      /* depth */
  280.   0,      /* xofs */
  281.   0,      /* yofs */
  282.   0,      /* waterlevel */
  283.   0,      /* ambient */
  284.   FALSE,  /* compensate */
  285.   FALSE,  /* invert */
  286.   LINEAR, /* type */
  287.   FALSE   /* tiled */
  288. };
  289.  
  290. static bumpmap_interface_t bmint =
  291. {
  292.   NULL,      /* preview */
  293.   NULL,      /* preview_adj_x */
  294.   NULL,      /* preview_adj_y */
  295.   0,         /* preview_width */
  296.   0,         /* preview_height */
  297.   0,         /* mouse_x */
  298.   0,         /* mouse_y */
  299.   0,         /* preview_xofs */
  300.   0,         /* preview_yofs */
  301.   DRAG_NONE, /* drag_mode */
  302.   NULL,      /* offset_adj_x */
  303.   NULL,      /* offset_adj_y */
  304.   NULL,      /* check_row_0 */
  305.   NULL,      /* check_row_1 */
  306.   NULL,      /* src_rows */
  307.   NULL,      /* bm_rows */
  308.   0,         /* src_yofs */
  309.   -1,        /* bm_yofs */
  310.   NULL,      /* bm_drawable */
  311.   0,         /* bm_width */
  312.   0,         /* bm_height */
  313.   0,         /* bm_bpp */
  314.   0,         /* bm_has_alpha */
  315.   { 0 },     /* src_rgn */
  316.   { 0 },     /* bm_rgn */
  317.   { 0 },     /* params */
  318.   FALSE      /* run */
  319. };
  320.  
  321. static GimpDrawable *drawable = NULL;
  322.  
  323. static gint       sel_x1, sel_y1;
  324. static gint       sel_x2, sel_y2;
  325. static gint       sel_width, sel_height;
  326. static gint       img_bpp;
  327. static gboolean   img_has_alpha;
  328.  
  329. /***** Macros *****/
  330.  
  331. #define MOD(x, y) \
  332.   ((x) < 0 ? ((y) - 1 - ((y) - 1 - (x)) % (y)) : (x) % (y))
  333.  
  334. /***** Functions *****/
  335.  
  336. MAIN ()
  337.  
  338. static void
  339. query (void)
  340. {
  341.   static GimpParamDef args[] =
  342.   {
  343.     { GIMP_PDB_INT32,    "run_mode",   "Interactive, non-interactive" },
  344.     { GIMP_PDB_IMAGE,    "image",      "Input image" },
  345.     { GIMP_PDB_DRAWABLE, "drawable",   "Input drawable" },
  346.     { GIMP_PDB_DRAWABLE, "bumpmap",    "Bump map drawable" },
  347.     { GIMP_PDB_FLOAT,    "azimuth",    "Azimuth" },
  348.     { GIMP_PDB_FLOAT,    "elevation",  "Elevation" },
  349.     { GIMP_PDB_INT32,    "depth",      "Depth" },
  350.     { GIMP_PDB_INT32,    "xofs",       "X offset" },
  351.     { GIMP_PDB_INT32,    "yofs",       "Y offset" },
  352.     { GIMP_PDB_INT32,    "waterlevel", "Level that full transparency should represent" },
  353.     { GIMP_PDB_INT32,    "ambient",    "Ambient lighting factor" },
  354.     { GIMP_PDB_INT32,    "compensate", "Compensate for darkening" },
  355.     { GIMP_PDB_INT32,    "invert",     "Invert bumpmap" },
  356.     { GIMP_PDB_INT32,    "type",       "Type of map (LINEAR (0), SPHERICAL (1), SINUOSIDAL (2))" }
  357.   };
  358.   static gint nargs = sizeof (args) / sizeof (args[0]);
  359.  
  360.   gimp_install_procedure ("plug_in_bump_map",
  361.               "Create an embossing effect using an image as a "
  362.               "bump map",
  363.               "This plug-in uses the algorithm described by John "
  364.               "Schlag, \"Fast Embossing Effects on Raster Image "
  365.               "Data\" in Graphics GEMS IV (ISBN 0-12-336155-9). "
  366.               "It takes a drawable to be applied as a bump "
  367.               "map to another image and produces a nice embossing "
  368.               "effect.",
  369.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  370.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  371.               PLUG_IN_VERSION,
  372.               N_("<Image>/Filters/Map/Bump Map..."),
  373.               "RGB*, GRAY*",
  374.               GIMP_PLUGIN,
  375.               nargs, 0,
  376.               args, NULL);
  377.  
  378.   gimp_install_procedure ("plug_in_bump_map_tiled",
  379.               "Create an embossing effect using a tiled image "
  380.               "as a bump map",
  381.               "This plug-in uses the algorithm described by John "
  382.               "Schlag, \"Fast Embossing Effects on Raster Image "
  383.               "Data\" in Graphics GEMS IV (ISBN 0-12-336155-9). "
  384.               "It takes a drawable to be tiled and applied as a "
  385.               "bump map to another image and produces a nice "
  386.               "embossing effect.",
  387.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  388.               "Federico Mena Quintero, Jens Lautenbacher & Sven Neumann",
  389.               PLUG_IN_VERSION,
  390.               NULL,
  391.               "RGB*, GRAY*",
  392.               GIMP_PLUGIN,
  393.               nargs, 0,
  394.               args, NULL);
  395. }
  396.  
  397. static void
  398. run (gchar   *name,
  399.      gint     nparams,
  400.      GimpParam  *param,
  401.      gint    *nreturn_vals,
  402.      GimpParam **return_vals)
  403. {
  404.   static GimpParam values[1];
  405.  
  406.   GimpRunModeType run_mode;
  407.   GimpPDBStatusType  status;
  408.  
  409.   INIT_I18N_UI();
  410.  
  411.   status   = GIMP_PDB_SUCCESS;
  412.   run_mode = param[0].data.d_int32;
  413.  
  414.   values[0].type          = GIMP_PDB_STATUS;
  415.   values[0].data.d_status = status;
  416.  
  417.   *nreturn_vals = 1;
  418.   *return_vals  = values;
  419.  
  420.   /* Get drawable information */
  421.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  422.  
  423.   gimp_drawable_mask_bounds (drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  424.  
  425.   sel_width     = sel_x2 - sel_x1;
  426.   sel_height    = sel_y2 - sel_y1;
  427.   img_bpp       = gimp_drawable_bpp (drawable->id);
  428.   img_has_alpha = gimp_drawable_has_alpha (drawable->id);
  429.  
  430.   /* See how we will run */
  431.   switch (run_mode)
  432.     {
  433.     case GIMP_RUN_INTERACTIVE:
  434.       /* Possibly retrieve data */
  435.       gimp_get_data (name, &bmvals);
  436.   
  437.       /* Get information from the dialog */
  438.       if (!bumpmap_dialog ())
  439.     return;
  440.  
  441.       break;
  442.  
  443.     case GIMP_RUN_NONINTERACTIVE:
  444.       /* Make sure all the arguments are present */
  445.       if (nparams != 14)
  446.     {
  447.       status = GIMP_PDB_CALLING_ERROR;
  448.     }
  449.       else
  450.     {
  451.       bmvals.bumpmap_id = param[3].data.d_drawable;
  452.       bmvals.azimuth    = param[4].data.d_float;
  453.       bmvals.elevation  = param[5].data.d_float;
  454.       bmvals.depth      = param[6].data.d_int32;
  455.       bmvals.depth      = param[6].data.d_int32;
  456.       bmvals.xofs       = param[7].data.d_int32;
  457.       bmvals.yofs       = param[8].data.d_int32;
  458.       bmvals.waterlevel = param[9].data.d_int32;
  459.       bmvals.ambient    = param[10].data.d_int32;
  460.       bmvals.compensate = param[11].data.d_int32;
  461.       bmvals.invert     = param[12].data.d_int32;
  462.       bmvals.type       = param[13].data.d_int32;
  463.       bmvals.tiled      = strcmp (name, "plug_in_bump_map_tiled") == 0;  
  464.     }
  465.       break;
  466.  
  467.     case GIMP_RUN_WITH_LAST_VALS:
  468.       /* Possibly retrieve data */
  469.       gimp_get_data (name, &bmvals);
  470.       break;
  471.  
  472.     default:
  473.       break;
  474.     }
  475.  
  476.   /* Bumpmap the image */
  477.  
  478.   if (status == GIMP_PDB_SUCCESS)
  479.     {
  480.       if ((gimp_drawable_is_rgb(drawable->id) ||
  481.        gimp_drawable_is_gray(drawable->id)))
  482.     {
  483.       /* Run! */
  484.       bumpmap ();
  485.  
  486.       /* If run mode is interactive, flush displays */
  487.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  488.         gimp_displays_flush ();
  489.  
  490.       /* Store data */
  491.       if (run_mode == GIMP_RUN_INTERACTIVE)
  492.         gimp_set_data (name, &bmvals, sizeof (bumpmap_vals_t));
  493.     }
  494.     }
  495.   else
  496.     status = GIMP_PDB_EXECUTION_ERROR;
  497.  
  498.   values[0].data.d_status = status;
  499.  
  500.   gimp_drawable_detach (drawable);
  501. }
  502.  
  503. static void
  504. bumpmap (void)
  505. {
  506.   bumpmap_params_t  params;
  507.   GimpDrawable     *bm_drawable;
  508.   GimpPixelRgn      src_rgn, dest_rgn, bm_rgn;
  509.   gint              bm_width, bm_height, bm_bpp, bm_has_alpha;
  510.   gint              yofs1, yofs2, yofs3;
  511.   gboolean          row_in_bumpmap;
  512.   guchar           *bm_row1, *bm_row2, *bm_row3, *bm_tmprow;
  513.   guchar           *src_row, *dest_row;
  514.   gint              y;
  515.   gint              progress;
  516.   gint              drawable_tiles_per_row, bm_tiles_per_row;
  517.  
  518. #if 0
  519.   g_print ("bumpmap: waiting... (pid %d)\n", getpid ());
  520.   kill (getpid (), SIGSTOP);
  521. #endif
  522.  
  523.   gimp_progress_init (_("Bump-mapping..."));
  524.     
  525.   /* Get the bumpmap drawable */
  526.   if (bmvals.bumpmap_id != -1)
  527.     bm_drawable = gimp_drawable_get (bmvals.bumpmap_id);
  528.   else
  529.     bm_drawable = drawable;
  530.  
  531.   if (!bm_drawable)
  532.     return;
  533.  
  534.   /* Get image information */
  535.   bm_width     = gimp_drawable_width (bm_drawable->id);
  536.   bm_height    = gimp_drawable_height (bm_drawable->id);
  537.   bm_bpp       = gimp_drawable_bpp (bm_drawable->id);
  538.   bm_has_alpha = gimp_drawable_has_alpha (bm_drawable->id);
  539.  
  540.   /* Set the tile cache size */
  541.   /* Compute number of tiles needed for one row of the drawable */
  542.   drawable_tiles_per_row =
  543.     1
  544.     + (sel_x2 + gimp_tile_width () - 1) / gimp_tile_width ()
  545.     - sel_x1 / gimp_tile_width ();
  546.   /* Compute number of tiles needed for one row of the bitmap */
  547.   bm_tiles_per_row = (bm_width + gimp_tile_width () - 1) / gimp_tile_width ();
  548.   /* Cache one row of source, destination and bitmap */
  549.   gimp_tile_cache_ntiles (bm_tiles_per_row + 2 * drawable_tiles_per_row);
  550.  
  551.   /* Initialize offsets */
  552.  
  553.   if (bmvals.tiled)
  554.     {
  555.       yofs2 = MOD (bmvals.yofs + sel_y1, bm_height);
  556.       yofs1 = MOD (yofs2 - 1, bm_height);
  557.       yofs3 = MOD (yofs2 + 1, bm_height);
  558.     }
  559.   else
  560.     {
  561.       yofs1 = 0;
  562.       yofs2 = 0;
  563.       yofs3 = CLAMP (yofs2 + 1, 0, bm_height - 1);
  564.     }
  565.  
  566.   /* Initialize row buffers */
  567.   bm_row1 = g_new (guchar, bm_width * bm_bpp);
  568.   bm_row2 = g_new (guchar, bm_width * bm_bpp);
  569.   bm_row3 = g_new (guchar, bm_width * bm_bpp);
  570.  
  571.   src_row  = g_new (guchar, sel_width * img_bpp);
  572.   dest_row = g_new (guchar, sel_width * img_bpp);
  573.  
  574.   /* Initialize pixel regions */
  575.   gimp_pixel_rgn_init (&src_rgn, drawable,
  576.                sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
  577.   gimp_pixel_rgn_init (&dest_rgn, drawable,
  578.                sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
  579.   gimp_pixel_rgn_init (&bm_rgn, bm_drawable,
  580.                0, 0, bm_width, bm_height, FALSE, FALSE);
  581.  
  582.   /* Bumpmap */
  583.  
  584.   bumpmap_init_params (¶ms);
  585.  
  586.   gimp_pixel_rgn_get_row (&bm_rgn, bm_row1, 0, yofs1, bm_width);
  587.   gimp_pixel_rgn_get_row (&bm_rgn, bm_row2, 0, yofs2, bm_width);
  588.   gimp_pixel_rgn_get_row (&bm_rgn, bm_row3, 0, yofs3, bm_width);
  589.  
  590.   bumpmap_convert_row (bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut);
  591.   bumpmap_convert_row (bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut);
  592.   bumpmap_convert_row (bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut);
  593.  
  594.   progress = 0;
  595.  
  596.   for (y = sel_y1; y < sel_y2; y++)
  597.     {
  598.       row_in_bumpmap = (y >= - bmvals.yofs && y < - bmvals.yofs + bm_height);
  599.  
  600.       gimp_pixel_rgn_get_row (&src_rgn, src_row, sel_x1, y, sel_width);
  601.  
  602.       bumpmap_row (src_row, dest_row, sel_width, img_bpp, img_has_alpha,
  603.            bm_row1, bm_row2, bm_row3, bm_width, bmvals.xofs,
  604.            bmvals.tiled, 
  605.            row_in_bumpmap,
  606.            ¶ms);
  607.  
  608.       gimp_pixel_rgn_set_row (&dest_rgn, dest_row, sel_x1, y, sel_width);
  609.  
  610.       /* Next line */
  611.  
  612.       if (bmvals.tiled || row_in_bumpmap)
  613.     {
  614.       bm_tmprow = bm_row1;
  615.       bm_row1   = bm_row2;
  616.       bm_row2   = bm_row3;
  617.       bm_row3   = bm_tmprow;
  618.  
  619.       if (++yofs2 == bm_height)
  620.         yofs2 = 0;
  621.  
  622.       if (bmvals.tiled)
  623.         yofs3 = MOD (yofs2 + 1, bm_height);
  624.       else
  625.         yofs3 = CLAMP (yofs2 + 1, 0, bm_height - 1);
  626.  
  627.       gimp_pixel_rgn_get_row (&bm_rgn, bm_row3, 0, yofs3, bm_width);
  628.       bumpmap_convert_row (bm_row3, bm_width, bm_bpp, bm_has_alpha,
  629.                    params.lut);
  630.     }
  631.  
  632.       gimp_progress_update ((double) ++progress / sel_height);
  633.     }
  634.  
  635.   /* Done */
  636.  
  637.   g_free (bm_row1);
  638.   g_free (bm_row2);
  639.   g_free (bm_row3);
  640.   g_free (src_row);
  641.   g_free (dest_row);
  642.  
  643.   if (bm_drawable != drawable)
  644.     gimp_drawable_detach (bm_drawable);
  645.  
  646.   gimp_drawable_flush (drawable);
  647.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  648.   gimp_drawable_update (drawable->id, sel_x1, sel_y1, sel_width, sel_height);
  649. }
  650.  
  651. static void
  652. bumpmap_init_params (bumpmap_params_t *params)
  653. {
  654.   gdouble azimuth;
  655.   gdouble elevation;
  656.   gint    lz, nz;
  657.   gint    i;
  658.   gdouble n;
  659.  
  660.   /* Convert to radians */
  661.   azimuth   = G_PI * bmvals.azimuth / 180.0;
  662.   elevation = G_PI * bmvals.elevation / 180.0;
  663.  
  664.   /* Calculate the light vector */
  665.   params->lx = cos(azimuth) * cos(elevation) * 255.0;
  666.   params->ly = sin(azimuth) * cos(elevation) * 255.0;
  667.   lz         = sin(elevation) * 255.0;
  668.  
  669.   /* Calculate constant Z component of surface normal */
  670.   nz           = (6 * 255) / bmvals.depth;
  671.   params->nz2  = nz * nz;
  672.   params->nzlz = nz * lz;
  673.  
  674.   /* Optimize for vertical normals */
  675.   params->background = lz;
  676.  
  677.   /* Calculate darkness compensation factor */
  678.   params->compensation = sin(elevation);
  679.  
  680.   /* Create look-up table for map type */
  681.   for (i = 0; i < 256; i++)
  682.     {
  683.       switch (bmvals.type)
  684.     {
  685.     case SPHERICAL:
  686.       n = i / 255.0 - 1.0;
  687.       params->lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5);
  688.       break;
  689.  
  690.     case SINUOSIDAL:
  691.       n = i / 255.0;
  692.       params->lut[i] = (int) (255.0 * (sin((-G_PI / 2.0) + G_PI * n) + 1.0) /
  693.                   2.0 + 0.5);
  694.       break;
  695.  
  696.     case LINEAR:
  697.     default:
  698.       params->lut[i] = i;
  699.     }
  700.  
  701.       if (bmvals.invert)
  702.     params->lut[i] = 255 - params->lut[i];
  703.     }
  704. }
  705.  
  706. static void
  707. bumpmap_row (guchar           *src,
  708.          guchar           *dest,
  709.          gint              width,
  710.          gint              bpp,
  711.          gint              has_alpha,
  712.          guchar           *bm_row1,
  713.          guchar           *bm_row2,
  714.          guchar           *bm_row3,
  715.          gint              bm_width,
  716.          gint              bm_xofs,
  717.          gboolean          tiled,
  718.          gboolean          row_in_bumpmap,       
  719.          bumpmap_params_t *params)
  720. {
  721.   gint xofs1, xofs2, xofs3;
  722.   gint shade;
  723.   gint ndotl;
  724.   gint nx, ny;
  725.   gint x, k;
  726.   gint pbpp;
  727.   gint result;
  728.   gint tmp;
  729.  
  730.   if (has_alpha)
  731.     pbpp = bpp - 1;
  732.   else
  733.     pbpp = bpp;
  734.  
  735.   tmp = bm_xofs + sel_x1;
  736.   xofs2 = MOD (tmp, bm_width);
  737.  
  738.   for (x = 0; x < width; x++)
  739.     {
  740.       /* Calculate surface normal from bump map */
  741.  
  742.       if (tiled || (row_in_bumpmap &&
  743.             x >= - tmp && x < - tmp + bm_width))
  744.     {
  745.       if (tiled)
  746.         {
  747.           xofs1 = MOD (xofs2 - 1, bm_width);
  748.           xofs3 = MOD (xofs2 + 1, bm_width);
  749.         }
  750.       else
  751.         {
  752.           xofs1 = CLAMP (xofs2 - 1, 0, bm_width - 1);
  753.           xofs3 = CLAMP (xofs2 + 1, 0, bm_width - 1);
  754.         }
  755.       nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
  756.         bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
  757.       ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
  758.         bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
  759.     }
  760.        else 
  761.      {
  762.        nx = ny = 0;
  763.      }
  764.  
  765.       /* Shade */
  766.  
  767.       if ((nx == 0) && (ny == 0))
  768.     shade = params->background;
  769.       else
  770.     {
  771.       ndotl = nx * params->lx + ny * params->ly + params->nzlz;
  772.  
  773.       if (ndotl < 0)
  774.         shade = params->compensation * bmvals.ambient;
  775.       else
  776.         {
  777.           shade = ndotl / sqrt(nx * nx + ny * ny + params->nz2);
  778.  
  779.           shade = shade + MAX(0, (255 * params->compensation - shade)) *
  780.         bmvals.ambient / 255;
  781.         }
  782.     }
  783.  
  784.       /* Paint */
  785.  
  786.       if (bmvals.compensate)
  787.     for (k = pbpp; k; k--)
  788.       {
  789.         result  = (*src++ * shade) / (params->compensation * 255);
  790.         *dest++ = MIN(255, result);
  791.       }
  792.       else
  793.     for (k = pbpp; k; k--)
  794.       *dest++ = *src++ * shade / 255;
  795.  
  796.       if (has_alpha)
  797.     *dest++ = *src++;
  798.  
  799.       /* Next pixel */
  800.  
  801.       if (++xofs2 == bm_width)
  802.     xofs2 = 0;
  803.     }
  804. }
  805.  
  806. static void
  807. bumpmap_convert_row (guchar *row, 
  808.              gint    width, 
  809.              gint    bpp, 
  810.              gint    has_alpha, 
  811.              guchar *lut)
  812. {
  813.   guchar *p;
  814.  
  815.   p = row;
  816.  
  817.   has_alpha = has_alpha ? 1 : 0;
  818.  
  819.   if (bpp >= 3)
  820.     for (; width; width--)
  821.       {
  822.     if (has_alpha)
  823.       *p++ = lut[(int) (bmvals.waterlevel +
  824.                 (((int) (INTENSITY (row[0], row[1], row[2]) + 0.5) - 
  825.                   bmvals.waterlevel) * 
  826.                  row[3]) / 255.0)];
  827.     else
  828.       *p++ = lut[(int) (INTENSITY (row[0], row[1], row[2]) + 0.5)];
  829.  
  830.     row += 3 + has_alpha;
  831.       }
  832.   else
  833.     for (; width; width--)
  834.       {
  835.     if (has_alpha)
  836.       *p++ = lut[bmvals.waterlevel +
  837.             ((row[0] - bmvals.waterlevel) * row[1]) / 255];
  838.     else
  839.       *p++ = lut[*row];
  840.  
  841.     row += 1 + has_alpha;
  842.       }
  843. }
  844.  
  845. static gint
  846. bumpmap_dialog (void)
  847. {
  848.   GtkWidget *dialog;
  849.   GtkWidget *top_vbox;
  850.   GtkWidget *hbox;
  851.   GtkWidget *frame;
  852.   GtkWidget *preview;
  853.   GtkWidget *vbox;
  854.   GtkWidget *sep;
  855.   GtkWidget *abox;
  856.   GtkWidget *pframe;
  857.   GtkWidget *ptable;
  858.   GtkWidget *scrollbar;
  859.   GtkWidget *table;
  860.   GtkWidget *right_vbox;
  861.   GtkWidget *option_menu;
  862.   GtkWidget *menu;
  863.   GtkWidget *button;
  864.   GtkObject *adj;
  865.   gint       i;
  866.   gint       row;
  867.  
  868.   gimp_ui_init ("bumpmap", TRUE);
  869.  
  870.   dialog = gimp_dialog_new (_("Bump Map"), "bumpmap",
  871.                 gimp_standard_help_func, "filters/bumpmap.html",
  872.                 GTK_WIN_POS_MOUSE,
  873.                 FALSE, TRUE, FALSE,
  874.  
  875.                 _("OK"), dialog_ok_callback,
  876.                 NULL, NULL, NULL, TRUE, FALSE,
  877.                 _("Cancel"), gtk_widget_destroy,
  878.                 NULL, 1, NULL, FALSE, TRUE,
  879.  
  880.                 NULL);
  881.  
  882.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  883.               GTK_SIGNAL_FUNC (gtk_main_quit),
  884.               NULL);
  885.  
  886.   top_vbox = gtk_vbox_new (FALSE, 4);
  887.   gtk_container_set_border_width (GTK_CONTAINER (top_vbox), 6);
  888.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_vbox,
  889.               FALSE, FALSE, 0);
  890.   gtk_widget_show (top_vbox);
  891.  
  892.   hbox = gtk_hbox_new (FALSE, 6);
  893.   gtk_box_pack_start (GTK_BOX (top_vbox), hbox, FALSE, FALSE, 0);
  894.   gtk_widget_show (hbox);
  895.  
  896.   /* Preview */
  897.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  898.   gtk_box_pack_start (GTK_BOX (hbox), abox, FALSE, FALSE, 0);
  899.   gtk_widget_show (abox);
  900.  
  901.   ptable = gtk_table_new (2, 2, FALSE);
  902.   gtk_container_set_border_width (GTK_CONTAINER (ptable), 4);
  903.   gtk_container_add (GTK_CONTAINER (abox), ptable);
  904.   gtk_widget_show (ptable);
  905.   
  906.   pframe = gtk_frame_new (NULL);
  907.   gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN);
  908.   gtk_container_set_border_width (GTK_CONTAINER (pframe), 0);
  909.   gtk_table_attach (GTK_TABLE (ptable), pframe, 0, 1, 0, 1, 
  910.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  911.   gtk_widget_show (pframe);
  912.  
  913.   bmint.preview_width  = MIN (sel_width, PREVIEW_SIZE);
  914.   bmint.preview_height = MIN (sel_height, PREVIEW_SIZE);
  915.  
  916.   bmint.preview = preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  917.   gtk_preview_size (GTK_PREVIEW (bmint.preview),
  918.             bmint.preview_width, bmint.preview_height);
  919.   gtk_container_add (GTK_CONTAINER (pframe), bmint.preview);
  920.   gtk_widget_show (bmint.preview);
  921.   
  922.   bmint.preview_adj_x = 
  923.     gtk_adjustment_new (0, 0, sel_width, 1, 10, bmint.preview_width);
  924.   if (sel_width > PREVIEW_SIZE)
  925.     {
  926.       scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (bmint.preview_adj_x));
  927.       gtk_table_attach (GTK_TABLE (ptable), scrollbar, 0, 1, 1, 2, 
  928.             GTK_FILL | GTK_EXPAND, 0, 0, 0);
  929.       gtk_widget_show (scrollbar);
  930.     }
  931.   
  932.   bmint.preview_adj_y = 
  933.     gtk_adjustment_new (0, 0, sel_height, 1, 10, bmint.preview_height);
  934.   if (sel_height > PREVIEW_SIZE)
  935.     {
  936.       scrollbar = gtk_vscrollbar_new (GTK_ADJUSTMENT (bmint.preview_adj_y));
  937.       gtk_table_attach (GTK_TABLE (ptable), scrollbar, 1, 2, 0,1, 
  938.             0, GTK_FILL | GTK_EXPAND, 0, 0);
  939.       gtk_widget_show (scrollbar);
  940.     }
  941.  
  942.   gtk_widget_set_events (bmint.preview, 
  943.              GDK_BUTTON_PRESS_MASK |
  944.              GDK_BUTTON_RELEASE_MASK | 
  945.              GDK_BUTTON_MOTION_MASK |
  946.              GDK_POINTER_MOTION_HINT_MASK);
  947.   gtk_signal_connect (GTK_OBJECT (bmint.preview), "event",
  948.               (GtkSignalFunc) dialog_preview_events,
  949.               NULL);
  950.   gtk_signal_connect (GTK_OBJECT (bmint.preview_adj_x), "value_changed",
  951.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal), 
  952.               &bmint.preview_xofs);
  953.   gtk_signal_connect (GTK_OBJECT (bmint.preview_adj_y), "value_changed",
  954.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal), 
  955.               &bmint.preview_yofs);
  956.  
  957.   dialog_init_preview ();
  958.  
  959.   /* Type of map */
  960.   frame =
  961.     gimp_radio_group_new2 (TRUE, _("Map Type"),
  962.                dialog_map_type_callback,
  963.                &bmvals.type, GINT_TO_POINTER (bmvals.type),
  964.  
  965.                _("Linear Map"),     GINT_TO_POINTER (LINEAR), NULL,
  966.                _("Spherical Map"),  GINT_TO_POINTER (SPHERICAL), NULL,
  967.                _("Sinuosidal Map"), GINT_TO_POINTER (SINUOSIDAL), NULL,
  968.  
  969.                NULL);
  970.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  971.   gtk_widget_show (frame);
  972.  
  973.   right_vbox = GTK_BIN (frame)->child;
  974.  
  975.   sep = gtk_hseparator_new ();
  976.   gtk_box_pack_start (GTK_BOX (right_vbox), sep, FALSE, FALSE, 1);
  977.   gtk_widget_show (sep);
  978.  
  979.   /* Compensate darkening */
  980.   button = gtk_check_button_new_with_label (_("Compensate for Darkening"));
  981.   gtk_box_pack_start (GTK_BOX (right_vbox), button, FALSE, FALSE, 0);
  982.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  983.                 bmvals.compensate ? TRUE : FALSE);
  984.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  985.               GTK_SIGNAL_FUNC (dialog_compensate_callback),
  986.               NULL);
  987.   gtk_widget_show (button);
  988.  
  989.   /* Invert bumpmap */
  990.   button = gtk_check_button_new_with_label (_("Invert Bumpmap"));
  991.   gtk_box_pack_start (GTK_BOX (right_vbox), button, FALSE, FALSE, 0);
  992.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  993.                 bmvals.invert ? TRUE : FALSE);
  994.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  995.               GTK_SIGNAL_FUNC (dialog_invert_callback),
  996.               NULL);
  997.   gtk_widget_show (button);
  998.  
  999.   /* Tile bumpmap */
  1000.   button = gtk_check_button_new_with_label (_("Tile Bumpmap"));
  1001.   gtk_box_pack_start (GTK_BOX (right_vbox), button, FALSE, FALSE, 0);
  1002.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  1003.                 bmvals.tiled ? TRUE : FALSE);
  1004.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  1005.               GTK_SIGNAL_FUNC (dialog_tiled_callback),
  1006.               NULL);
  1007.   gtk_widget_show (button);  
  1008.  
  1009.   frame = gtk_frame_new (_("Parameter Settings"));
  1010.   gtk_box_pack_start (GTK_BOX (top_vbox), frame, FALSE, FALSE, 0);
  1011.   gtk_widget_show (frame);
  1012.  
  1013.   vbox = gtk_vbox_new (FALSE, 2);
  1014.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  1015.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1016.   gtk_widget_show (vbox);
  1017.  
  1018.   /* Bump map menu */
  1019.   table = gtk_table_new (1, 2, FALSE);
  1020.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1021.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  1022.   gtk_widget_show (table);
  1023.  
  1024.   option_menu = gtk_option_menu_new ();
  1025.   menu = gimp_drawable_menu_new (dialog_constrain,
  1026.                  dialog_bumpmap_callback,
  1027.                  NULL,
  1028.                  bmvals.bumpmap_id);
  1029.   gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
  1030.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  1031.                  _("Bump Map:"), 1.0, 0.5,
  1032.                  option_menu, 2, TRUE);
  1033.  
  1034.   sep = gtk_hseparator_new ();
  1035.   gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0);
  1036.   gtk_widget_show (sep);
  1037.  
  1038.   /* Table for bottom controls */
  1039.  
  1040.   table = gtk_table_new (7, 3, FALSE);
  1041.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  1042.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  1043.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  1044.   gtk_widget_show (table);
  1045.  
  1046.   /* Controls */
  1047.   row = 0;
  1048.  
  1049.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1050.                   _("Azimuth:"), SCALE_WIDTH, 0,
  1051.                   bmvals.azimuth, 0.0, 360.0, 1.0, 15.0, 2,
  1052.                   TRUE, 0, 0,
  1053.                   NULL, NULL);
  1054.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1055.               GTK_SIGNAL_FUNC (dialog_dscale_update),
  1056.               &bmvals.azimuth);
  1057.  
  1058.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1059.                   _("Elevation:"), SCALE_WIDTH, 0,
  1060.                   bmvals.elevation, 0.5, 90.0, 1.0, 5.0, 2,
  1061.                   TRUE, 0, 0,
  1062.                   NULL, NULL);
  1063.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1064.               GTK_SIGNAL_FUNC (dialog_dscale_update),
  1065.               &bmvals.elevation);
  1066.  
  1067.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
  1068.                   _("Depth:"), SCALE_WIDTH, 0,
  1069.                   bmvals.depth, 1.0, 65.0, 1.0, 5.0, 0,
  1070.                   TRUE, 0, 0,
  1071.                   NULL, NULL);
  1072.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1073.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1074.               &bmvals.depth);
  1075.   gtk_table_set_row_spacing (GTK_TABLE (table), row++, 8);
  1076.  
  1077.   bmint.offset_adj_x = adj = 
  1078.     gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1079.               _("X Offset:"), SCALE_WIDTH, 0,
  1080.               bmvals.xofs, -1000.0, 1001.0, 1.0, 10.0, 0,
  1081.               TRUE, 0, 0,
  1082.               NULL, NULL);
  1083.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1084.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1085.               &bmvals.xofs);
  1086.  
  1087.   bmint.offset_adj_y = adj = 
  1088.     gimp_scale_entry_new (GTK_TABLE (table), 0, row,
  1089.               _("Y Offset:"), SCALE_WIDTH, 0,
  1090.               bmvals.yofs, -1000.0, 1001.0, 1.0, 10.0, 0,
  1091.               TRUE, 0, 0,
  1092.               NULL, NULL);
  1093.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1094.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1095.               &bmvals.yofs);
  1096.   gtk_table_set_row_spacing (GTK_TABLE (table), row++, 8);
  1097.  
  1098.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1099.                   _("Waterlevel:"), SCALE_WIDTH, 0,
  1100.                   bmvals.waterlevel, 0.0, 255.0, 1.0, 8.0, 0,
  1101.                   TRUE, 0, 0,
  1102.                   NULL, NULL);
  1103.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1104.               GTK_SIGNAL_FUNC (dialog_iscale_update_full),
  1105.               &bmvals.waterlevel);
  1106.  
  1107.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row++,
  1108.                   _("Ambient:"), SCALE_WIDTH, 0,
  1109.                   bmvals.ambient, 0.0, 255.0, 1.0, 8.0, 0,
  1110.                   TRUE, 0, 0,
  1111.                   NULL, NULL);
  1112.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1113.               GTK_SIGNAL_FUNC (dialog_iscale_update_normal),
  1114.               &bmvals.ambient);
  1115.  
  1116.   /* Done */
  1117.  
  1118.   gtk_widget_show (dialog);
  1119.  
  1120.   gtk_main ();
  1121.   gdk_flush ();
  1122.  
  1123.   g_free (bmint.check_row_0);
  1124.   g_free (bmint.check_row_1);
  1125.  
  1126.   for (i = 0; i < bmint.preview_height; i++)
  1127.     g_free (bmint.src_rows[i]);
  1128.  
  1129.   g_free (bmint.src_rows);
  1130.  
  1131.   for (i = 0; i < (bmint.preview_height + 2); i++)
  1132.     g_free (bmint.bm_rows[i]);
  1133.  
  1134.   g_free (bmint.bm_rows);
  1135.  
  1136.   if (bmint.bm_drawable != drawable)
  1137.     gimp_drawable_detach (bmint.bm_drawable);
  1138.  
  1139.   return bmint.run;
  1140. }
  1141.  
  1142. static void
  1143. dialog_init_preview (void)
  1144. {
  1145.   gint x;
  1146.     
  1147.   /* Create checkerboard rows */
  1148.  
  1149.   bmint.check_row_0 = g_new (guchar, bmint.preview_width);
  1150.   bmint.check_row_1 = g_new (guchar, bmint.preview_width);
  1151.  
  1152.   for (x = 0; x < bmint.preview_width; x++)
  1153.     if ((x / GIMP_CHECK_SIZE) & 1)
  1154.       {
  1155.     bmint.check_row_0[x] = GIMP_CHECK_DARK  * 255;
  1156.     bmint.check_row_1[x] = GIMP_CHECK_LIGHT * 255;
  1157.       }
  1158.     else
  1159.       {
  1160.     bmint.check_row_0[x] = GIMP_CHECK_LIGHT * 255;
  1161.     bmint.check_row_1[x] = GIMP_CHECK_DARK  * 255;
  1162.       }
  1163.  
  1164.   /* Initialize source rows */
  1165.  
  1166.   gimp_pixel_rgn_init (&bmint.src_rgn, drawable,
  1167.                sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
  1168.  
  1169.   bmint.src_rows = g_new (guchar *, bmint.preview_height);
  1170.  
  1171.   for (x = 0; x < bmint.preview_height; x++)
  1172.     bmint.src_rows[x]  = g_new (guchar, sel_width * 4);
  1173.  
  1174.   dialog_fill_src_rows (0,
  1175.             bmint.preview_height,
  1176.             sel_y1 + bmint.preview_yofs);
  1177.  
  1178.   /* Initialize bumpmap rows */
  1179.  
  1180.   bmint.bm_rows = g_new (guchar *, bmint.preview_height + 2);
  1181.  
  1182.   for (x = 0; x < (bmint.preview_height + 2); x++)
  1183.     bmint.bm_rows[x] = NULL;
  1184. }
  1185.  
  1186. static gint
  1187. dialog_preview_events (GtkWidget *widget, 
  1188.                GdkEvent  *event)
  1189. {
  1190.   gint            x, y;
  1191.   gint            dx, dy;
  1192.   GdkEventButton *bevent;
  1193.     
  1194.   gtk_widget_get_pointer (widget, &x, &y);
  1195.  
  1196.   bevent = (GdkEventButton *) event;
  1197.  
  1198.   switch (event->type)
  1199.     {
  1200.     case GDK_BUTTON_PRESS:
  1201.       switch (bevent->button)
  1202.     {
  1203.     case 1:
  1204.     case 2:  
  1205.       if (bevent->state & GDK_SHIFT_MASK)
  1206.         bmint.drag_mode = DRAG_BUMPMAP;
  1207.       else
  1208.         bmint.drag_mode = DRAG_SCROLL;
  1209.       break;
  1210.  
  1211.     case 3:
  1212.       bmint.drag_mode = DRAG_BUMPMAP;
  1213.       break;
  1214.  
  1215.     default:
  1216.       return FALSE;
  1217.     }
  1218.  
  1219.       bmint.mouse_x = x;
  1220.       bmint.mouse_y = y;
  1221.  
  1222.       gtk_grab_add (widget);
  1223.  
  1224.       break;
  1225.  
  1226.     case GDK_BUTTON_RELEASE:
  1227.       if (bmint.drag_mode != DRAG_NONE)
  1228.     {
  1229.       gtk_grab_remove (widget);
  1230.       bmint.drag_mode = DRAG_NONE;
  1231.       dialog_update_preview ();
  1232.     }
  1233.  
  1234.       break;
  1235.  
  1236.     case GDK_MOTION_NOTIFY:
  1237.       dx = x - bmint.mouse_x;
  1238.       dy = y - bmint.mouse_y;
  1239.  
  1240.       bmint.mouse_x = x;
  1241.       bmint.mouse_y = y;
  1242.  
  1243.       if ((dx == 0) && (dy == 0))
  1244.     break;
  1245.  
  1246.       switch (bmint.drag_mode)
  1247.     {
  1248.     case DRAG_SCROLL:
  1249.       bmint.preview_xofs = CLAMP (bmint.preview_xofs - dx,
  1250.                       0,
  1251.                       sel_width - bmint.preview_width);
  1252.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.preview_adj_x), 
  1253.                         &bmint.preview_xofs);
  1254.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.preview_adj_x), 
  1255.                     bmint.preview_xofs);
  1256.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.preview_adj_x), 
  1257.                           &bmint.preview_xofs);
  1258.       bmint.preview_yofs = CLAMP (bmint.preview_yofs - dy,
  1259.                       0,
  1260.                       sel_height - bmint.preview_height);
  1261.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.preview_adj_y), 
  1262.                         &bmint.preview_yofs);
  1263.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.preview_adj_y), 
  1264.                     bmint.preview_yofs);
  1265.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.preview_adj_y), 
  1266.                           &bmint.preview_yofs);
  1267.       
  1268.       break;
  1269.  
  1270.     case DRAG_BUMPMAP:
  1271.       bmvals.xofs = CLAMP (bmvals.xofs - dx, -1000, 1000);
  1272.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.offset_adj_x), 
  1273.                         &bmvals.xofs);
  1274.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.offset_adj_x), 
  1275.                     bmvals.xofs);
  1276.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.offset_adj_x), 
  1277.                           &bmvals.xofs);
  1278.  
  1279.       bmvals.yofs = CLAMP (bmvals.yofs - dy, -1000, 1000);
  1280.       gtk_signal_handler_block_by_data (GTK_OBJECT (bmint.offset_adj_y), 
  1281.                         &bmvals.yofs);
  1282.       gtk_adjustment_set_value (GTK_ADJUSTMENT (bmint.offset_adj_y), 
  1283.                     bmvals.yofs);
  1284.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (bmint.offset_adj_y), 
  1285.                           &bmvals.yofs);
  1286.  
  1287.       break;
  1288.  
  1289.     default:
  1290.       return FALSE;
  1291.     }
  1292.  
  1293.       dialog_update_preview ();
  1294.  
  1295.       break; 
  1296.  
  1297.     default:
  1298.       break;
  1299.     }
  1300.  
  1301.   return FALSE;
  1302. }
  1303.  
  1304. static void
  1305. dialog_new_bumpmap (gboolean init_offsets)
  1306. {
  1307.   GtkAdjustment   *adj;
  1308.   gint             i;
  1309.   gint             yofs;
  1310.   gint             bump_offset_x;
  1311.   gint             bump_offset_y;
  1312.   gint             draw_offset_y;
  1313.   gint             draw_offset_x;
  1314.  
  1315.   /* Get drawable */
  1316.   if (bmint.bm_drawable && (bmint.bm_drawable != drawable))
  1317.     gimp_drawable_detach (bmint.bm_drawable);
  1318.  
  1319.   if (bmvals.bumpmap_id != -1)
  1320.     bmint.bm_drawable = gimp_drawable_get (bmvals.bumpmap_id);
  1321.   else
  1322.     bmint.bm_drawable = drawable;
  1323.  
  1324.   if (!bmint.bm_drawable)
  1325.     return;
  1326.  
  1327.   /* Get sizes */
  1328.   bmint.bm_width     = gimp_drawable_width (bmint.bm_drawable->id);
  1329.   bmint.bm_height    = gimp_drawable_height (bmint.bm_drawable->id);
  1330.   bmint.bm_bpp       = gimp_drawable_bpp (bmint.bm_drawable->id);
  1331.   bmint.bm_has_alpha = gimp_drawable_has_alpha (bmint.bm_drawable->id);
  1332.  
  1333.   if (init_offsets)
  1334.     {      
  1335.       gimp_drawable_offsets (bmint.bm_drawable->id, &bump_offset_x, &bump_offset_y);
  1336.       gimp_drawable_offsets (drawable->id, &draw_offset_x, &draw_offset_y);
  1337.       
  1338.       bmvals.xofs = draw_offset_x - bump_offset_x;
  1339.       bmvals.yofs = draw_offset_y - bump_offset_y;
  1340.     }
  1341.  
  1342.   adj = (GtkAdjustment *) bmint.offset_adj_x;
  1343.   if (adj)
  1344.     {
  1345.       adj->value = bmvals.xofs;
  1346.       gtk_signal_handler_block_by_data (GTK_OBJECT (adj), &bmvals.xofs);
  1347.       gtk_adjustment_value_changed (adj);
  1348.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), &bmvals.xofs);
  1349.     }
  1350.   
  1351.   adj = (GtkAdjustment *) bmint.offset_adj_y;
  1352.   if (adj)
  1353.     {
  1354.       adj->value = bmvals.yofs;
  1355.       gtk_signal_handler_block_by_data (GTK_OBJECT (adj), &bmvals.yofs);
  1356.       gtk_adjustment_value_changed (adj);
  1357.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), &bmvals.yofs);
  1358.     }
  1359.   
  1360.   /* Initialize pixel region */
  1361.  
  1362.   gimp_pixel_rgn_init (&bmint.bm_rgn, bmint.bm_drawable,
  1363.                0, 0, bmint.bm_width, bmint.bm_height, FALSE, FALSE);
  1364.  
  1365.   /* Initialize row buffers */
  1366.  
  1367.   yofs = bmvals.yofs + bmint.preview_yofs - 1; /* Minus 1 for conv. matrix */
  1368.   yofs = MOD (yofs, bmint.bm_height);
  1369.  
  1370.   bmint.bm_yofs = yofs;
  1371.  
  1372.   for (i = 0; i < (bmint.preview_height + 2); i++)
  1373.     {
  1374.       if (bmint.bm_rows[i])
  1375.     g_free (bmint.bm_rows[i]);
  1376.  
  1377.       bmint.bm_rows[i] = g_new (guchar, bmint.bm_width * bmint.bm_bpp);
  1378.     }
  1379.  
  1380.   bumpmap_init_params (&bmint.params);
  1381.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, yofs);
  1382. }
  1383.  
  1384. static void
  1385. dialog_update_preview (void)
  1386. {
  1387.   static guchar dest_row[PREVIEW_SIZE * 4];
  1388.   static guchar preview_row[PREVIEW_SIZE * 3];
  1389.  
  1390.   guchar *check_row;
  1391.   guchar  check;
  1392.   gint    xofs;
  1393.   gint    x, y;
  1394.   guchar *sp, *p;
  1395.  
  1396.   bumpmap_init_params (&bmint.params);
  1397.  
  1398.   /* Scroll the row buffers */
  1399.  
  1400.   dialog_scroll_src ();
  1401.   dialog_scroll_bumpmap ();
  1402.  
  1403.   /* Bumpmap */
  1404.  
  1405.   xofs = bmint.preview_xofs;
  1406.  
  1407.   for (y = 0; y < bmint.preview_height; y++)
  1408.     {
  1409.       gint isfirst = ((y == - bmvals.yofs - bmint.preview_yofs - sel_y1)
  1410.               && ! bmvals.tiled) ? 1 : 0;
  1411.       gint islast = (y == (- bmvals.yofs - bmint.preview_yofs - sel_y1
  1412.                + bmint.bm_height - 1) && ! bmvals.tiled) ? 1 : 0;
  1413.       bumpmap_row (bmint.src_rows[y] + 4 * xofs, dest_row,
  1414.            bmint.preview_width, 4, TRUE,
  1415.            bmint.bm_rows[y + isfirst],
  1416.            bmint.bm_rows[y + 1],
  1417.            bmint.bm_rows[y + 2 - islast],
  1418.            bmint.bm_width, xofs + bmvals.xofs,
  1419.            bmvals.tiled, 
  1420.            y >= - bmvals.yofs - bmint.preview_yofs - sel_y1 &&
  1421.            y < (- bmvals.yofs - bmint.preview_yofs - sel_y1
  1422.             + bmint.bm_height),
  1423.            &bmint.params);
  1424.  
  1425.       /* Paint row */
  1426.  
  1427.       sp = dest_row;
  1428.       p  = preview_row;
  1429.  
  1430.       if ((y / GIMP_CHECK_SIZE) & 1)
  1431.     check_row = bmint.check_row_0;
  1432.       else
  1433.     check_row = bmint.check_row_1;
  1434.  
  1435.       for (x = 0; x < bmint.preview_width; x++)
  1436.     {
  1437.       check = check_row[x];
  1438.  
  1439.       p[0] = check + ((sp[0] - check) * sp[3]) / 255;
  1440.       p[1] = check + ((sp[1] - check) * sp[3]) / 255;
  1441.       p[2] = check + ((sp[2] - check) * sp[3]) / 255;
  1442.  
  1443.       sp += 4;
  1444.       p  += 3;
  1445.     }
  1446.  
  1447.       gtk_preview_draw_row (GTK_PREVIEW(bmint.preview),
  1448.                 preview_row, 0, y, bmint.preview_width);
  1449.     }
  1450.  
  1451.   gtk_widget_draw (bmint.preview, NULL);
  1452.   gdk_flush ();
  1453. }
  1454.  
  1455. #define SWAP_ROWS(a, b, t) { t = a; a = b; b = t; }
  1456.  
  1457. static void
  1458. dialog_scroll_src (void)
  1459. {
  1460.   gint    yofs;
  1461.   gint    y, ofs;
  1462.   guchar *tmp;
  1463.  
  1464.   yofs = bmint.preview_yofs;
  1465.  
  1466.   if (yofs == bmint.src_yofs)
  1467.     return;
  1468.  
  1469.   if (yofs < bmint.src_yofs)
  1470.     {
  1471.       ofs = bmint.src_yofs - yofs;
  1472.  
  1473.       /* Scroll useful rows... */
  1474.  
  1475.       if (ofs < bmint.preview_height)
  1476.     for (y = (bmint.preview_height - 1); y >= ofs; y--)
  1477.       SWAP_ROWS (bmint.src_rows[y], bmint.src_rows[y - ofs], tmp);
  1478.  
  1479.       /* ... and get the new ones */
  1480.  
  1481.       dialog_fill_src_rows (0, MIN (ofs, bmint.preview_height), sel_y1 + yofs);
  1482.     }
  1483.   else
  1484.     {
  1485.       ofs = yofs - bmint.src_yofs;
  1486.  
  1487.       /* Scroll useful rows... */
  1488.  
  1489.       if (ofs < bmint.preview_height)
  1490.     for (y = 0; y < (bmint.preview_height - ofs); y++)
  1491.       SWAP_ROWS (bmint.src_rows[y], bmint.src_rows[y + ofs], tmp);
  1492.  
  1493.       /* ... and get the new ones */
  1494.  
  1495.       dialog_fill_src_rows ((bmint.preview_height -
  1496.                  MIN (ofs, bmint.preview_height)),
  1497.                 MIN (ofs, bmint.preview_height),
  1498.                 (sel_y1 + yofs + bmint.preview_height -
  1499.                  MIN (ofs, bmint.preview_height)));
  1500.     }
  1501.  
  1502.   bmint.src_yofs = yofs;
  1503. }
  1504.  
  1505. static void
  1506. dialog_scroll_bumpmap (void)
  1507. {
  1508.   gint    yofs;
  1509.   gint    y, ofs;
  1510.   guchar *tmp;
  1511.  
  1512.   yofs = bmvals.yofs + bmint.preview_yofs - 1; /* Minus 1 for conv. matrix */
  1513.   yofs = MOD (yofs, bmint.bm_height);
  1514.  
  1515.   if (yofs == bmint.bm_yofs)
  1516.     return;
  1517.  
  1518.   if (yofs < bmint.bm_yofs)
  1519.     {
  1520.       ofs = bmint.bm_yofs - yofs;
  1521.  
  1522.       /* Scroll useful rows... */
  1523.  
  1524.       if (ofs < (bmint.preview_height + 2))
  1525.     for (y = (bmint.preview_height + 1); y >= ofs; y--)
  1526.       SWAP_ROWS (bmint.bm_rows[y], bmint.bm_rows[y - ofs], tmp);
  1527.  
  1528.       /* ... and get the new ones */
  1529.  
  1530.       dialog_fill_bumpmap_rows (0,
  1531.                 MIN (ofs, bmint.preview_height + 2),
  1532.                 yofs);
  1533.     }
  1534.   else
  1535.     {
  1536.       ofs = yofs - bmint.bm_yofs;
  1537.  
  1538.       /* Scroll useful rows... */
  1539.  
  1540.       if (ofs < (bmint.preview_height + 2))
  1541.     for (y = 0; y < (bmint.preview_height + 2 - ofs); y++)
  1542.       SWAP_ROWS (bmint.bm_rows[y], bmint.bm_rows[y + ofs], tmp);
  1543.  
  1544.       /* ... and get the new ones */
  1545.  
  1546.       dialog_fill_bumpmap_rows ((bmint.preview_height + 2 -
  1547.                  MIN (ofs, bmint.preview_height + 2)),
  1548.                 MIN (ofs, bmint.preview_height + 2),
  1549.                 (yofs + bmint.preview_height + 2 -
  1550.                  MIN (ofs, bmint.preview_height + 2)) %
  1551.                 bmint.bm_height);
  1552.     }
  1553.  
  1554.   bmint.bm_yofs = yofs;
  1555. }
  1556.  
  1557. static void
  1558. dialog_get_rows (GimpPixelRgn  *pr, 
  1559.          guchar    **rows, 
  1560.          gint        x, 
  1561.          gint        y, 
  1562.          gint        width, 
  1563.          gint        height)
  1564. {
  1565.   /* This is shamelessly ripped off from gimp_pixel_rgn_get_rect().
  1566.    * Its function is exactly the same, but it can fetch an image
  1567.    * rectangle to a sparse buffer which is defined as separate
  1568.    * rows instead of one big linear region.
  1569.    */
  1570.  
  1571.   GimpTile  *tile;
  1572.   guchar *src, *dest;
  1573.   gint    xstart, ystart;
  1574.   gint    xend, yend;
  1575.   gint    xboundary;
  1576.   gint    yboundary;
  1577.   gint    xstep, ystep;
  1578.   gint    b, bpp;
  1579.   gint    tx, ty;
  1580.   gint    tile_width, tile_height;
  1581.  
  1582.   tile_width  = gimp_tile_width();
  1583.   tile_height = gimp_tile_height();
  1584.  
  1585.   bpp = pr->bpp;
  1586.  
  1587.   xstart = x;
  1588.   ystart = y;
  1589.   xend   = x + width;
  1590.   yend   = y + height;
  1591.   ystep  = 0; /* Shut up -Wall */
  1592.  
  1593.   while (y < yend)
  1594.     {
  1595.       x = xstart;
  1596.  
  1597.       while (x < xend)
  1598.     {
  1599.       tile = gimp_drawable_get_tile2 (pr->drawable, pr->shadow, x, y);
  1600.       gimp_tile_ref (tile);
  1601.  
  1602.       xstep     = tile->ewidth - (x % tile_width);
  1603.       ystep     = tile->eheight - (y % tile_height);
  1604.       xboundary = x + xstep;
  1605.       yboundary = y + ystep;
  1606.       xboundary = MIN (xboundary, xend);
  1607.       yboundary = MIN (yboundary, yend);
  1608.  
  1609.       for (ty = y; ty < yboundary; ty++)
  1610.         {
  1611.           src  = tile->data + tile->bpp * (tile->ewidth * (ty % tile_height) +
  1612.                            (x % tile_width));
  1613.           dest = rows[ty - ystart] + bpp * (x - xstart);
  1614.  
  1615.           for (tx = x; tx < xboundary; tx++)
  1616.         for (b = bpp; b; b--)
  1617.           *dest++ = *src++;
  1618.         }
  1619.  
  1620.       gimp_tile_unref (tile, FALSE);
  1621.  
  1622.       x += xstep;
  1623.     }
  1624.  
  1625.       y += ystep;
  1626.     }
  1627. }
  1628.  
  1629. static void
  1630. dialog_fill_src_rows (gint start, 
  1631.               gint how_many, 
  1632.               gint yofs)
  1633. {
  1634.   gint    x;
  1635.   gint    y;
  1636.   guchar *sp;
  1637.   guchar *p;
  1638.  
  1639.   dialog_get_rows (&bmint.src_rgn,
  1640.            bmint.src_rows + start,
  1641.            sel_x1,
  1642.            yofs,
  1643.            sel_width,
  1644.            how_many);
  1645.  
  1646.   /* Convert to RGBA.  We move backwards! */
  1647.  
  1648.   for (y = start; y < (start + how_many); y++)
  1649.     {
  1650.       sp = bmint.src_rows[y] + img_bpp * sel_width - 1;
  1651.       p  = bmint.src_rows[y] + 4 * sel_width - 1;
  1652.  
  1653.       for (x = 0; x < sel_width; x++)
  1654.     {
  1655.       if (img_has_alpha)
  1656.         *p-- = *sp--;
  1657.       else
  1658.         *p-- = 255;
  1659.  
  1660.       if (img_bpp < 3)
  1661.         {
  1662.           *p-- = *sp;
  1663.           *p-- = *sp;
  1664.           *p-- = *sp--;
  1665.         }
  1666.       else
  1667.         {
  1668.           *p-- = *sp--;
  1669.           *p-- = *sp--;
  1670.           *p-- = *sp--;
  1671.         }
  1672.     }
  1673.     }
  1674. }
  1675.  
  1676. static void
  1677. dialog_fill_bumpmap_rows (gint start, 
  1678.               gint how_many, 
  1679.               gint yofs)
  1680. {
  1681.   gint buf_row_ofs;
  1682.   gint remaining;
  1683.   gint this_pass;
  1684.  
  1685.   /* Adapt to offset of selection */
  1686.   yofs = MOD (yofs + sel_y1, bmint.bm_height);
  1687.  
  1688.   buf_row_ofs = start;
  1689.   remaining   = how_many;
  1690.  
  1691.   while (remaining > 0)
  1692.     {
  1693.       this_pass = MIN (remaining, bmint.bm_height - yofs);
  1694.  
  1695.       dialog_get_rows (&bmint.bm_rgn,
  1696.                bmint.bm_rows + buf_row_ofs,
  1697.                0,
  1698.                yofs,
  1699.                bmint.bm_width,
  1700.                this_pass);
  1701.  
  1702.       yofs         = (yofs + this_pass) % bmint.bm_height;
  1703.       remaining   -= this_pass;
  1704.       buf_row_ofs += this_pass;
  1705.     }
  1706.  
  1707.   /* Convert rows */
  1708.  
  1709.   for (; how_many; how_many--)
  1710.     {
  1711.       bumpmap_convert_row (bmint.bm_rows[start],
  1712.                bmint.bm_width,
  1713.                bmint.bm_bpp,
  1714.                bmint.bm_has_alpha,
  1715.                bmint.params.lut);
  1716.  
  1717.       start++;
  1718.     }
  1719. }
  1720.  
  1721. static void
  1722. dialog_compensate_callback (GtkWidget *widget, 
  1723.                 gpointer   data)
  1724. {
  1725.   bmvals.compensate = GTK_TOGGLE_BUTTON (widget)->active;
  1726.  
  1727.   dialog_update_preview ();
  1728. }
  1729.  
  1730. static void
  1731. dialog_invert_callback (GtkWidget *widget, 
  1732.             gpointer   data)
  1733. {
  1734.   bmvals.invert = GTK_TOGGLE_BUTTON (widget)->active;
  1735.  
  1736.   bumpmap_init_params (&bmint.params);
  1737.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1738.   dialog_update_preview ();
  1739. }
  1740.  
  1741. static void
  1742. dialog_tiled_callback (GtkWidget *widget, 
  1743.             gpointer   data)
  1744. {
  1745.   bmvals.tiled = GTK_TOGGLE_BUTTON (widget)->active;
  1746.  
  1747.   bumpmap_init_params (&bmint.params);
  1748.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1749.   dialog_update_preview ();
  1750. }
  1751.  
  1752. static void
  1753. dialog_map_type_callback (GtkWidget *widget, 
  1754.               gpointer   data)
  1755. {
  1756.   gimp_radio_button_update (widget, data);
  1757.  
  1758.   if (GTK_TOGGLE_BUTTON (widget)->active)
  1759.     {
  1760.       bumpmap_init_params (&bmint.params);
  1761.       dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1762.       dialog_update_preview ();
  1763.     }
  1764. }
  1765.  
  1766. static gint
  1767. dialog_constrain (gint32   image_id, 
  1768.           gint32   drawable_id, 
  1769.           gpointer data)
  1770. {
  1771.   if (drawable_id == -1)
  1772.     return TRUE;
  1773.  
  1774.   return (gimp_drawable_is_rgb (drawable_id) ||
  1775.       gimp_drawable_is_gray (drawable_id));
  1776. }
  1777.  
  1778. static void
  1779. dialog_bumpmap_callback (gint32   id, 
  1780.              gpointer data)
  1781. {
  1782.   if (bmvals.bumpmap_id == id)
  1783.     {
  1784.       dialog_new_bumpmap (FALSE);
  1785.     }
  1786.   else
  1787.     {
  1788.       bmvals.bumpmap_id = id;
  1789.       dialog_new_bumpmap (TRUE);
  1790.     }
  1791.   dialog_update_preview ();
  1792. }
  1793.  
  1794. static void
  1795. dialog_dscale_update (GtkAdjustment *adjustment, 
  1796.               gdouble       *value)
  1797. {
  1798.   gimp_double_adjustment_update (adjustment, value);
  1799.  
  1800.   dialog_update_preview ();
  1801. }
  1802.  
  1803. static void
  1804. dialog_iscale_update_normal (GtkAdjustment *adjustment, 
  1805.                  gint          *value)
  1806. {
  1807.   gimp_int_adjustment_update (adjustment, value);
  1808.  
  1809.   dialog_update_preview ();
  1810. }
  1811.  
  1812. static void
  1813. dialog_iscale_update_full (GtkAdjustment *adjustment, 
  1814.                gint          *value)
  1815. {
  1816.   gimp_int_adjustment_update (adjustment, value);
  1817.  
  1818.   bumpmap_init_params (&bmint.params);
  1819.   dialog_fill_bumpmap_rows (0, bmint.preview_height + 2, bmint.bm_yofs);
  1820.   dialog_update_preview ();
  1821. }
  1822.  
  1823. static void
  1824. dialog_ok_callback (GtkWidget *widget, 
  1825.             gpointer   data)
  1826. {
  1827.   bmint.run = TRUE;
  1828.  
  1829.   gtk_widget_destroy (GTK_WIDGET (data));
  1830. }
  1831.